
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
  <meta charset="utf-8">
  <title>多线程内存问题分析之mprotect方法 - Yebangyu's Blog</title>
  <meta name="author" content="Yebangyu">

  
  <meta name="description" content="本文介绍多线程环境下内存问题的mprotect分析方法">
  <meta name="keywords" content="并行编程 多线程 内存问题 mprotect">

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  
  <link rel="canonical" href="http://www.yebangyu.org/blog/2016/02/01/detectmemoryghostinmultithread/">
  <link href="/favicon.png" rel="icon">
  <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
  <link href="/atom.xml" rel="alternate" title="Yebangyu's Blog" type="application/atom+xml">
  <script src="/javascripts/modernizr-2.0.js"></script>
  <script src="//ajax.lug.ustc.edu.cn/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script>!window.jQuery && document.write(unescape('%3Cscript src="/javascripts/libs/jquery.min.js"%3E%3C/script%3E'))</script>
  <script src="/javascripts/octopress.js" type="text/javascript"></script>
  <!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="//fonts.lug.ustc.edu.cn/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>

  

</head>

<body   >
  <header role="banner"><hgroup>
  <h1><a href="/">Yebangyu's Blog</a></h1>
  
    <h2>Fond of Concurrency Programming and Machine Learning</h2>
  
</hgroup>

</header>
  <nav role="navigation"><ul class="subscription" data-subscription="rss">
  <li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
  
</ul>
  
<form action="https://www.google.com/search" method="get">
  <fieldset role="search">
    <input type="hidden" name="sitesearch" value="www.yebangyu.org">
    <input class="search" type="text" name="q" results="0" placeholder="Search"/>
  </fieldset>
</form>
  
<ul class="main-navigation">
  <li><a href="/">Blog</a></li>
  <li><a href="/blog/archives">Archives</a></li>
  <li><a href="/about">About Me</a></li>
</ul>

</nav>
  <div id="main">
    <div id="content">
      <div>
<article class="hentry" role="article">
  
  <header>
    
      <h1 class="entry-title">多线程内存问题分析之mprotect方法</h1>
    
    
      <p class="meta">
        




<time class='entry-date' datetime='2016-02-01T22:24:25+08:00'><span class='date'><span class='date-month'>Feb</span> <span class='date-day'>1</span><span class='date-suffix'>st</span>, <span class='date-year'>2016</span></span> <span class='time'>10:24 pm</span></time>
        
      </p>
    
  </header>


<div class="entry-content"><p>多线程中的内存问题，一直被认为是噩梦般的存在，几乎只有高手、大仙才能解决。除了大量的打log、gdb调试、code review以及依靠多年的经验和直觉之外，有没有一些分析的手段和工具呢？答案是肯定的。本文首先介绍其中的一种：mprotect大法。通过mprotect，保护特定的感兴趣的内存，当有线程改写该区域时，会产生一个中断，我们在中断处理函数中把调用栈等信息打印出来。这是大概的思路，不过其中的问题很多，我们慢慢道来。</p>

<!--more-->

<h2 id="section">原理</h2>

<h3 id="mprotect">mprotect函数</h3>

<p>mprotect函数的原型如下：</p>

<p>int mprotect(const void *addr, size_t len, int prot);</p>

<p>其中addr是待保护的内存首地址，必须按页对齐；len是待保护内存的大小，必须是页的整数倍，prot代表模式，可能的取值有PROT_READ（表示可读）、PROT_WRITE（可写）等。</p>

<p>不同体系结构和操作系统，一页的大小不尽相同。如何获得页大小呢？通过PAGE_SIZE宏或者getpagesize()系统调用即可。</p>

<h3 id="section-1">定制中断处理函数</h3>

<p>当线程试图对我们已保护（成只读）的内存进行篡改时，默认情况下程序会收到SIGSEGV错误而退出。能不能不退出并且把相应的调用栈打印出来分析？当然可以。通过如下代码注册你定制的中断处理函数即可：</p>

<pre><code>struct sigaction act;
act.sa_sigaction = your_handler;
sigemptyset(&amp;act.sa_mask);
act.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &amp;act, NULL) == -1) {
  perror("Register hanlder failed");
  exit(EXIT_FAILURE);
}
</code></pre>

<p>这样，控制流就会到达你编写的your_handler函数上。而your_handler的函数原型是：</p>

<p>void your_handler(int sig, siginfo_t *si, void *unused)；</p>

<p>编写your_handler函数即可？是的，不过这里面有两个注意事项：</p>

<p>1，中断处理函数里不应该调用内存分配函数，否则可能会引起double fault。因此，不适合调用backtrace_symbols（内部会动态分配内存），而是通过backtrace_symbols_fd直接将调用栈信息直接刷到文件中。</p>

<p>2，中断处理函数中应该恢复被保护内存为可写，否则会引起死循环。（再次中断并进入咱们编写的函数）</p>

<h3 id="section-2">封装</h3>

<p>为了方便使用，我封装了一个类，供参考：</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
<span class="line-number">31</span>
<span class="line-number">32</span>
<span class="line-number">33</span>
<span class="line-number">34</span>
<span class="line-number">35</span>
<span class="line-number">36</span>
<span class="line-number">37</span>
<span class="line-number">38</span>
<span class="line-number">39</span>
<span class="line-number">40</span>
<span class="line-number">41</span>
<span class="line-number">42</span>
<span class="line-number">43</span>
<span class="line-number">44</span>
<span class="line-number">45</span>
<span class="line-number">46</span>
<span class="line-number">47</span>
<span class="line-number">48</span>
<span class="line-number">49</span>
<span class="line-number">50</span>
<span class="line-number">51</span>
<span class="line-number">52</span>
<span class="line-number">53</span>
<span class="line-number">54</span>
<span class="line-number">55</span>
<span class="line-number">56</span>
<span class="line-number">57</span>
<span class="line-number">58</span>
<span class="line-number">59</span>
<span class="line-number">60</span>
<span class="line-number">61</span>
<span class="line-number">62</span>
<span class="line-number">63</span>
<span class="line-number">64</span>
<span class="line-number">65</span>
<span class="line-number">66</span>
<span class="line-number">67</span>
<span class="line-number">68</span>
<span class="line-number">69</span>
<span class="line-number">70</span>
<span class="line-number">71</span>
<span class="line-number">72</span>
<span class="line-number">73</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include &lt;fcntl.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;signal.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;stdio.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;stdlib.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;string.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;stdint.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;sys/mman.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;sys/stat.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;unistd.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;sys/user.h&gt;</span>
</span><span class="line"><span class="cp">#include &lt;execinfo.h&gt;</span>
</span><span class="line"><span class="k">class</span> <span class="nc">MemoryDetector</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line"><span class="k">public</span><span class="o">:</span>
</span><span class="line">  <span class="k">typedef</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">segv_handler</span><span class="p">)</span> <span class="p">(</span><span class="kt">int</span> <span class="n">sig</span><span class="p">,</span> <span class="kt">siginfo_t</span> <span class="o">*</span><span class="n">si</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">);</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">void</span> <span class="nf">init</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span><span class="p">)</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="n">register_handler</span><span class="p">(</span><span class="n">handler</span><span class="p">);</span>
</span><span class="line">    <span class="n">fd_</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="o">|</span><span class="n">O_CREAT</span><span class="p">,</span> <span class="mi">777</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">int</span> <span class="nf">protect</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">)</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="n">address_</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">uint64_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
</span><span class="line">    <span class="n">len_</span> <span class="o">=</span> <span class="n">len</span><span class="p">;</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">start_address</span> <span class="o">=</span> <span class="p">(</span><span class="n">address_</span> <span class="o">&gt;&gt;</span> <span class="n">PAGE_SHIFT</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">PAGE_SHIFT</span><span class="p">;</span>
</span><span class="line">    <span class="k">return</span> <span class="n">mprotect</span><span class="p">(</span><span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">void</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">start_address</span><span class="p">),</span> <span class="n">PAGE_SIZE</span><span class="p">,</span> <span class="n">PROT_READ</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">int</span> <span class="nf">umprotect</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">p</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">)</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">tmp_address_</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">uint64_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">start_address</span> <span class="o">=</span> <span class="p">(</span><span class="n">tmp_address_</span> <span class="o">&gt;&gt;</span> <span class="n">PAGE_SHIFT</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">PAGE_SHIFT</span><span class="p">;</span>
</span><span class="line">    <span class="k">return</span> <span class="n">mprotect</span><span class="p">(</span><span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">void</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">start_address</span><span class="p">),</span> <span class="n">PAGE_SIZE</span><span class="p">,</span> <span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">PROT_WRITE</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">int</span> <span class="nf">umprotect</span><span class="p">()</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">start_address</span> <span class="o">=</span> <span class="p">(</span><span class="n">address_</span> <span class="o">&gt;&gt;</span> <span class="n">PAGE_SHIFT</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">PAGE_SHIFT</span><span class="p">;</span>
</span><span class="line">    <span class="k">return</span> <span class="n">mprotect</span><span class="p">(</span><span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">void</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">start_address</span><span class="p">),</span> <span class="n">PAGE_SIZE</span><span class="p">,</span> <span class="n">PROT_READ</span> <span class="o">|</span> <span class="n">PROT_WRITE</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">void</span> <span class="nf">finish</span><span class="p">()</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="n">close</span><span class="p">(</span><span class="n">fd_</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line"><span class="k">private</span><span class="o">:</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">void</span> <span class="n">register_handler</span><span class="p">(</span><span class="n">segv_handler</span> <span class="n">sh</span><span class="p">)</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="k">struct</span> <span class="n">sigaction</span> <span class="n">act</span><span class="p">;</span>
</span><span class="line">    <span class="n">act</span><span class="p">.</span><span class="n">sa_sigaction</span> <span class="o">=</span> <span class="n">sh</span><span class="p">;</span>
</span><span class="line">    <span class="n">sigemptyset</span><span class="p">(</span><span class="o">&amp;</span><span class="n">act</span><span class="p">.</span><span class="n">sa_mask</span><span class="p">);</span>
</span><span class="line">    <span class="n">act</span><span class="p">.</span><span class="n">sa_flags</span> <span class="o">=</span> <span class="n">SA_SIGINFO</span><span class="p">;</span>
</span><span class="line">    <span class="k">if</span><span class="p">(</span><span class="n">sigaction</span><span class="p">(</span><span class="n">SIGSEGV</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">act</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">){</span>
</span><span class="line">      <span class="n">perror</span><span class="p">(</span><span class="s">&quot;Register hanlder failed&quot;</span><span class="p">);</span>
</span><span class="line">      <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_FAILURE</span><span class="p">);</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">void</span> <span class="n">handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">sig</span><span class="p">,</span> <span class="kt">siginfo_t</span> <span class="o">*</span><span class="n">si</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="kt">uint64_t</span> <span class="n">address</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">uint64_t</span><span class="o">&gt;</span><span class="p">(</span><span class="n">si</span><span class="o">-&gt;</span><span class="n">si_addr</span><span class="p">);</span>
</span><span class="line">    <span class="k">if</span> <span class="p">(</span><span class="n">address</span> <span class="o">&gt;=</span> <span class="n">address_</span> <span class="o">&amp;&amp;</span> <span class="n">address</span> <span class="o">&lt;</span> <span class="n">address_</span> <span class="o">+</span> <span class="n">len_</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line">      <span class="n">umprotect</span><span class="p">(</span><span class="n">si</span><span class="o">-&gt;</span><span class="n">si_addr</span><span class="p">,</span> <span class="n">PAGE_SIZE</span><span class="p">);</span>
</span><span class="line">      <span class="n">my_backtrace</span><span class="p">();</span>
</span><span class="line">    <span class="p">}</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">void</span> <span class="n">my_backtrace</span><span class="p">()</span>
</span><span class="line">  <span class="p">{</span>
</span><span class="line">    <span class="k">const</span> <span class="kt">int</span> <span class="n">N</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
</span><span class="line">    <span class="kt">void</span><span class="o">*</span> <span class="n">array</span><span class="p">[</span><span class="mi">100</span><span class="p">];</span>
</span><span class="line">    <span class="kt">size_t</span> <span class="n">size</span> <span class="o">=</span> <span class="n">backtrace</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="n">N</span><span class="p">);</span>
</span><span class="line">    <span class="n">backtrace_symbols_fd</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">fd_</span><span class="p">);</span>
</span><span class="line">  <span class="p">}</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">uint64_t</span> <span class="n">address_</span><span class="p">;</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">int</span> <span class="n">len_</span><span class="p">;</span>
</span><span class="line">  <span class="k">static</span> <span class="kt">int</span> <span class="n">fd_</span><span class="p">;</span>
</span><span class="line"><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>

<p>这个封装还存在一些问题，比如缺少错误处理，待保护内存必须在一页内等。读者诸君可以根据需要自行完善。</p>

<h2 id="section-3">实战</h2>

<p>来个例子,实战一下吧</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
</pre></td><td class="code"><pre><code class="c++"><span class="line"><span class="cp">#include &quot;test.h&quot; </span><span class="c1">//就是上面封装的MemoryDetector类</span>
</span><span class="line"><span class="cp">#include &lt;thread&gt;</span>
</span><span class="line"><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
</span><span class="line"><span class="kt">uint64_t</span> <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">address_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="kt">int</span> <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">len_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="kt">int</span> <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">fd_</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="c1">///////////////////////////////////////</span>
</span><span class="line"><span class="kt">int</span> <span class="o">*</span><span class="n">p</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">g</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">usleep</span><span class="p">(</span><span class="mi">2000000</span><span class="p">);</span>
</span><span class="line">  <span class="kt">char</span> <span class="o">*</span><span class="n">q</span> <span class="o">=</span> <span class="k">reinterpret_cast</span><span class="o">&lt;</span><span class="kt">char</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
</span><span class="line">  <span class="o">*</span><span class="p">(</span><span class="n">q</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">111</span><span class="p">;</span><span class="c1">//非法篡改！！！</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">void</span> <span class="nf">f</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="n">p</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">int</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span><span class="line">  <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">protect</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
</span><span class="line"><span class="p">}</span>
</span><span class="line"><span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
</span><span class="line"><span class="p">{</span>
</span><span class="line">  <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">path</span> <span class="o">=</span> <span class="s">&quot;result.tmp&quot;</span><span class="p">;</span><span class="c1">//调用栈信息存放路径</span>
</span><span class="line">  <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">init</span><span class="p">(</span><span class="n">path</span><span class="p">);</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">t1</span><span class="p">(</span><span class="n">f</span><span class="p">);</span>
</span><span class="line">  <span class="n">std</span><span class="o">::</span><span class="kr">thread</span> <span class="n">t2</span><span class="p">(</span><span class="n">g</span><span class="p">);</span>
</span><span class="line">  <span class="n">t1</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="n">t2</span><span class="p">.</span><span class="n">join</span><span class="p">();</span>
</span><span class="line">  <span class="n">MemoryDetector</span><span class="o">::</span><span class="n">finish</span><span class="p">();</span>
</span><span class="line">  <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>用如下方式编译链接以上程序：</p>

<pre><code>g++ -g -rdynamic -std=c++11 -pthread  test.cpp -o test
</code></pre>

<p>程序运行结束后，打开result.tmp文件，看到如下内容：</p>

<pre><code>./test(_ZN14MemoryDetector12my_backtraceEv+0x26)[0x405ce8]
./test(_ZN14MemoryDetector7handlerEiP7siginfoPv+0x60)[0x405cc0]
/lib64/libpthread.so.0[0x339a80f500]
./test(_Z1gv+0x25)[0x405909]
./test(_ZNSt6thread5_ImplIPFvvEE6_M_runEv+0x16)[0x406e2c]
/usr/lib64/libstdc++.so.6[0x3a6f6b6490]
/lib64/libpthread.so.0[0x339a807851]
/lib64/libc.so.6(clone+0x6d)[0x339a4e767d]
</code></pre>

<p>注意其中的第四行：./test(_Z1gv+0x25)[0x405909]。使用addr2line命令：</p>

<pre><code>addr2line -e test 0x405909
</code></pre>

<p>获得非法篡改的代码位置：</p>

<p>/home/yebangyu/test.cpp:13</p>

<p>真相大白了。</p>

<h2 id="section-4">感谢</h2>

<p>我最早知道这个方法，是从我主管<a href="http://weibo.com/yangzhifeng83">杨志丰</a>先生那儿以及他的<a href="http://blog.csdn.net/killmice/article/details/38443343">这篇</a>文章。</p>
</div>


  <footer>
    <p class="meta">
      
  

<span class="byline author vcard">Posted by <span class="fn">Yebangyu</span></span>

      




<time class='entry-date' datetime='2016-02-01T22:24:25+08:00'><span class='date'><span class='date-month'>Feb</span> <span class='date-day'>1</span><span class='date-suffix'>st</span>, <span class='date-year'>2016</span></span> <span class='time'>10:24 pm</span></time>
      

<span class="categories">
  
    <a class='category' href='/blog/categories/bing-xing-bian-cheng/'>并行编程</a>
  
</span>


    </p>
    
      <div class="sharing">
  
  
  
</div>

    
    <p class="meta">
      
        <a class="basic-alignment left" href="/blog/2016/01/29/insidethebloomfilter/" title="Previous Post: 深入解析Bloom Filter(中)">&laquo; 深入解析Bloom Filter(中)</a>
      
      
        <a class="basic-alignment right" href="/blog/2016/02/16/materials-in-concurrency-programming/" title="Next Post: Materials In Concurrency Programming">Materials In Concurrency Programming &raquo;</a>
      
    </p>
  </footer>
</article>


</div>

<aside class="sidebar">
  
    <section>
  <h1>Recent Posts</h1>
  <ul id="recent_posts">
    
      <li class="post">
        <a href="/blog/2017/03/11/2017/">2017技术成长之路</a>
      </li>
    
      <li class="post">
        <a href="/blog/2017/02/17/virtualfunctionandvariadicparametertemplate/">虚函数和变长参数模板的妙用</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/25/singleton/">Singleton与多线程</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/04/introductiontohazardpointer/">Lock Free中的Hazard Pointer(下)</a>
      </li>
    
      <li class="post">
        <a href="/blog/2016/12/03/gccandperfopt/">性能优化的那些传说和迷思</a>
      </li>
    
  </ul>
</section>
<section>
  <h1>Friends' Link</h1>
  <ul>
    <li>
	  <li><a href="http://www.chongh.wiki/">Diting0x</a></li>
	  <li><a href="http://www.xiaolili.net/">wangli</a></li>
	  <li><a href="http://www.skykewei.top">dukewei</a></li>
	  <li><a href="http://irwenqiang.github.io">chenwenqiang</a></li>
      <li><a href="http://www.armsword.com">duruofei</a></li>
    </li>
  </ul>
</section><section>
  <h1>Yebangyu</h1>
  <p>福建人。热爱历史、K歌、NBA</p>
  <p>帝都码农</p>
  <p>历史学家，专治秦汉史</p>
</section>
<section>
 <h1>Categories</h1>
 <ul id="categories">
  <li class='category'><a href='/blog/categories/c-plus-plus/'>c++ (11)</a></li>
<li class='category'><a href='/blog/categories/soupen/'>soupen (4)</a></li>
<li class='category'><a href='/blog/categories/web/'>web (1)</a></li>
<li class='category'><a href='/blog/categories/qi-ta/'>其他 (5)</a></li>
<li class='category'><a href='/blog/categories/li-shi/'>历史 (2)</a></li>
<li class='category'><a href='/blog/categories/bing-xing-bian-cheng/'>并行编程 (20)</a></li>
<li class='category'><a href='/blog/categories/xing-neng-you-hua/'>性能优化 (2)</a></li>
<li class='category'><a href='/blog/categories/suan-fa/'>算法 (4)</a></li>
<li class='category'><a href='/blog/categories/bian-yi-lian-jie/'>编译链接 (2)</a></li>

 </ul>
</section>




  
</aside>


    </div>
  </div>
  <footer role="contentinfo"><!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  jax: ["input/TeX", "output/HTML-CSS"],
  tex2jax: {
    inlineMath: [ ['$', '$'] ],
    displayMath: [ ['$$', '$$']],
    processEscapes: true,
    skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
  },
  messageStyle: "none",
  "HTML-CSS": { preferredFont: "TeX", availableFonts: ["STIX","TeX"] }
});
</script>
<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML" type="text/javascript"></script>
<p>
  Copyright &copy; 2017 - Yebangyu -
  <span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1257548193'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s11.cnzz.com/z_stat.php%3Fid%3D1257548193' type='text/javascript'%3E%3C/script%3E"));</script>

</footer>
  











</body>
</html>
